package com.ccx.coachsite.weibo.auth2.net;


import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnRouteParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.net.wifi.WifiManager;

import com.ccx.coachsite.util.TelephoneUtil;
import com.ccx.coachsite.weibo.json.JSONException;
import com.ccx.coachsite.weibo.json.JSONObject;


public class HttpUtil {

	private static myX509TrustManager xtm = new myX509TrustManager();

    private static myHostnameVerifier hnv = new myHostnameVerifier();
    
    public static final String BOUNDARY = "7cd4a6d158c";
    public static final String MP_BOUNDARY = "--" + BOUNDARY;
    public static final String END_MP_BOUNDARY = "--" + BOUNDARY + "--";
    public static final String MULTIPART_FORM_DATA = "multipart/form-data";

    public static final String HTTPMETHOD_POST = "POST";
    public static final String HTTPMETHOD_GET = "GET";
    public static final String HTTPMETHOD_DELETE = "DELETE";

    private static final int SET_CONNECTION_TIMEOUT = 50000;
    private static final int SET_SOCKET_TIMEOUT = 200000;
    
    /**
     * 获取Https的连接对象
     * @param url
     * @return
     * @throws Exception
     */
	public static HttpsURLConnection getHttpsConnection(String url) throws Exception
	{
		SSLContext sslContext = null;
        try {
            sslContext = SSLContext.getInstance("TLS"); //或SSL
            X509TrustManager[] xtmArray = new X509TrustManager[] {xtm};
            sslContext.init(null, xtmArray, new java.security.SecureRandom());
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
        if (sslContext != null) {
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        }
        
        HttpsURLConnection.setDefaultHostnameVerifier(hnv);
        
		HttpsURLConnection conn=null;
		int retryCount=4;//偿试次数4次
		for(int i=0;i<retryCount;i++)
		{
			try {
				conn=(HttpsURLConnection) new URL(url).openConnection();
				conn.setConnectTimeout(5000); //连接超时5秒
				conn.setReadTimeout(5000);   //读取超进5秒
				conn.setDoInput(true);
				conn.setDoOutput(true);
				return conn;
			} catch (Exception e) {
				if(i==retryCount-1)
					throw e;
			}
		}
		
		return null;
	}//end getHttpsConnection
	
	/**
	 * 发送Http请求
	 * @param context
	 * @param httpMethod //请求方式POST\GET
	 * @param url        请求地址
	 * @param access_token 访问授权码
	 * @param params     传递的参数
	 * @param file       上传的文件
	 * @return
	 * @throws Exception
	 */
	public static Response httpRequest(
									Context context,
									String httpMethod,
									String url,
									String access_token,
									HashMap<String, String> params,
									InputStream is) throws Exception
	{
		//网络异常
		if(!TelephoneUtil.isNetworkAvailable(context))
			throw new SocketTimeoutException();
		HttpsURLConnection con=null;
		OutputStream osw=null;
		try {
			
			StringBuffer paramBuffer = new StringBuffer();
			//授权码不为空，表示已登录状态
			if(access_token!=null)
				paramBuffer.append(URLEncoder.encode("access_token","UTF-8")).append("=").append(URLEncoder.encode(access_token, "UTF-8")).append("&");
			
			//将参数组合成 name=value&name1=value1&...格式
			if(params!=null)
			{
				Iterator<Entry<String, String>> entryIter=params.entrySet().iterator();
				while(entryIter.hasNext())
				{
					Entry<String, String> entry=entryIter.next();
					paramBuffer.append(URLEncoder.encode(entry.getKey(),"UTF-8")).append("=").append(URLEncoder.encode(entry.getValue(), "UTF-8")).append("&");
				}
				//去掉最后一个"&"号
				paramBuffer.deleteCharAt(paramBuffer.length()-1);
				
			}//end if
			
			//不是POST提交，将参数接在URL之后
			if(!httpMethod.equalsIgnoreCase("POST"))
			{
				url+="?"+paramBuffer.toString();
			}
			
			//获取HTTPS的连接
			con=HttpUtil.getHttpsConnection(url);
			//请求方式
			con.setRequestMethod(httpMethod);
			
			if(httpMethod.equalsIgnoreCase("POST"))
			{
				
				con.setUseCaches(false);
				con.setRequestProperty("Cache-Control","no-cache");
				con.setRequestProperty("Connection", "Keep-Alive");
				con.setRequestProperty("Charset", "UTF-8");
				//上传文件 
				if(is!=null)
				{
					String BOUNDARY = "--------------et567z"; // 数据分隔线
					String MULTIPART_FORM_DATA = "Multipart/form-data";
					
					con.setRequestProperty("Content-Type", MULTIPART_FORM_DATA+ ";boundary=" + BOUNDARY);
					
					if(params!=null)
					{
						params.put("access_token", access_token);
						StringBuilder sb = new StringBuilder();
						Iterator<Entry<String, String>> entryIter=params.entrySet().iterator();
						while(entryIter.hasNext())
						{
							Entry<String, String> entry=entryIter.next();
							sb.append("--");
							sb.append(BOUNDARY);
							sb.append("\r\n");
							sb.append("Content-Disposition: form-data; name=\""
									+ entry.getKey() + "\"\r\n\r\n");
							sb.append(entry.getValue());
							sb.append("\r\n");
						}
						osw = new DataOutputStream(con.getOutputStream());
						osw.write(sb.toString().getBytes());// 发送表单字段数据
					}//end if
					
					//上传文件部份
					StringBuilder split = new StringBuilder();
					split.append("--");
					split.append(BOUNDARY);
					split.append("\r\n");
					split.append("Content-Disposition: form-data;name=\"pic\";filename=\"temp.jpg\"\r\n");
					split.append("Content-Type: image/jpg\r\n\r\n");
					osw.write(split.toString().getBytes());
					//osw.write(binaryBytes);
					//FileInputStream fis=new FileInputStream(file);
					BufferedInputStream bis=new BufferedInputStream(is);
					byte[] buffer=new byte[1024];
					int len=-1;
					while((len=bis.read(buffer))!=-1)
					{
						osw.write(buffer, 0, len);
						osw.flush();
					}
					bis.close();
					osw.write("\r\n".getBytes());
					
					byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();// 数据结束标志
					osw.write(end_data);
					osw.flush();
					osw.close();
					
				}else{
					//非文件上传的POST提交
					//内容类型
					con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
					byte[] bytes = paramBuffer.toString().getBytes("UTF-8");
					con.setRequestProperty("Content-Length", Integer.toString(bytes.length));
					con.connect();
					osw = con.getOutputStream();
					osw.write(bytes);
					osw.flush();
					osw.close();
					
				}//end if
				
			}//end if
			Response response=new Response(con);
			checkResponse(response);
	        return response;
	        
		} catch (Exception e) {
			throw e;
		} finally{
			try {
				if(osw!=null)
					osw.close();
			} catch (Exception e2) {
			}
		}//end try
		
		
	}//end httpRequest
	
	/**
	 * 校验结果是否正确
	 * @param response
	 * @throws Exception
	 */
	private static void checkResponse(Response response) throws Exception
	{
		String err = null;
        int errCode = 0;
        JSONObject json = null;
		try {
			json = response.asJSONObject();
		} catch (JSONException jsone) {
			throw jsone;
		}
		
		if(json!=null){
			try {
				err = json.getString("error");
				errCode = json.getInt("error_code");
			} catch (Exception e) {
			}
		}
		
		if(errCode!=0)
			throw new WeiboException(String.format(err), errCode);
		
	}//end handleError
	
	/**
     * 获取Https的连接对象
     * @param url
     * @return
     * @throws Exception
     */
	public static HttpURLConnection getHttpConnection(String url) throws Exception
	{
        
		HttpURLConnection conn=null;
		int retryCount=4;//偿试次数4次
		for(int i=0;i<retryCount;i++)
		{
			try {
				conn=(HttpURLConnection) new URL(url).openConnection();
				conn.setConnectTimeout(5000); //连接超时5秒
				conn.setReadTimeout(5000);   //读取超时5秒
				conn.setDoInput(true);
				conn.setDoOutput(true);
				conn.connect();
				return conn;
			} catch (Exception e) {
				if(conn!=null)
					conn.disconnect();
				if(i==retryCount-1)
					throw e;
			} 
		}
		
		return null;
		
	}//end getHttpsConnection
	
	public static String encodeUrl(HashMap<String, String> params) {
        if (params == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        Iterator<String> keyIter= params.keySet().iterator();
        while(keyIter.hasNext())
        {
        	String key=keyIter.next();
        	  if (first)
                  first = false;
              else
                  sb.append("&");
              sb.append(URLEncoder.encode(key) + "="
                      + URLEncoder.encode(params.get(key)));
        }
        return sb.toString();
        
    }
	
	public static Response openUrl(Context context, String url, String method,
            HashMap<String, String> params,InputStream is, String accessToken) throws Exception {
		
		//网络异常
		if(!TelephoneUtil.isNetworkAvailable(context))
			throw new SocketTimeoutException();
		
		String result = "";
        try {
            HttpClient client = getNewHttpClient(context);
            HttpUriRequest request = null;
            ByteArrayOutputStream bos = null;
            if (method.equals("GET")) {
                url = url + "?" + encodeUrl(params);
                HttpGet get = new HttpGet(url);
                request = get;
            } else if (method.equals("POST")) {
                HttpPost post = new HttpPost(url);
                byte[] data = null;
                bos = new ByteArrayOutputStream(1024 * 50);
                if (is!=null) {//文件上传
                    paramToUpload(bos, params);
                    post.setHeader("Content-Type", MULTIPART_FORM_DATA + "; boundary=" + BOUNDARY);
                    imageContentToUpload(bos, is);
                } else {
                    post.setHeader("Content-Type", "application/x-www-form-urlencoded");
                    String postParam = encodeParameters(params);
                    data = postParam.getBytes("UTF-8");
                    bos.write(data);
                }
                data = bos.toByteArray();
                bos.close();
                // UrlEncodedFormEntity entity = getPostParamters(params);
                ByteArrayEntity formEntity = new ByteArrayEntity(data);
                post.setEntity(formEntity);
                request = post;
            } else if (method.equals("DELETE")) {
                request = new HttpDelete(url);
            }
            request.setHeader("Authorization","OAuth2 "+accessToken);
            request.setHeader("Accept-Encoding", "gzip");
            request.setHeader("User-Agent", System.getProperties().getProperty("http.agent")
                    + " WeiboAndroidSDK");
            
            HttpResponse response = client.execute(request);
            StatusLine status = response.getStatusLine();
            int statusCode = status.getStatusCode();

            if (statusCode != 200) {
                result = read(response);
                String err = null;
                int errCode = 0;
				try {
					JSONObject json = new JSONObject(result);
					err = json.getString("error");
					errCode = json.getInt("error_code");
				} catch (JSONException e) {
					throw e;
				}
				
				throw new WeiboException(String.format(err), errCode);
            }
            result = read(response);
            Response wbResponse=new Response(result, statusCode);
            return wbResponse;
        } catch (Exception e) {
            throw e;
        }
    }
	
    
	
	private static void paramToUpload(OutputStream baos, HashMap<String, String> params)throws WeiboException 
	{
		if (null == params || params.size()==0) {
            return ;
        }
		Iterator<String> keyIter=params.keySet().iterator();
		while(keyIter.hasNext())
		{
			String key=keyIter.next();
			StringBuilder temp = new StringBuilder(10);
		    temp.setLength(0);
		    temp.append(MP_BOUNDARY).append("\r\n");
		    temp.append("content-disposition: form-data; name=\"").append(key).append("\"\r\n\r\n");
		    temp.append(params.get(key)).append("\r\n");
		    byte[] res = temp.toString().getBytes();
		    try {
		        baos.write(res);
		    } catch (IOException e) {
		        throw new WeiboException(e);
		    }
		}
	}
	
	/**
     * Upload image into output stream .
     * 
     * @param out
     *            : output stream for uploading weibo
     * @param imgpath
     *            : bitmap for uploading
     * @return void
     */
    private static void imageContentToUpload(OutputStream out, InputStream is)
            throws Exception {
        StringBuilder temp = new StringBuilder();

        temp.append(MP_BOUNDARY).append("\r\n");
        temp.append("Content-Disposition: form-data; name=\"pic\"; filename=\"")
                .append("news_image").append("\"\r\n");
        String filetype = "image/png";
        temp.append("Content-Type: ").append(filetype).append("\r\n\r\n");
        byte[] res = temp.toString().getBytes();
        BufferedInputStream bis = null;
        try {
            out.write(res);
            //imgpath.compress(CompressFormat.PNG, 75, out);
            bis=new BufferedInputStream(is);
			byte[] buffer=new byte[1024];
			int len=-1;
			while((len=bis.read(buffer))!=-1)
			{
				out.write(buffer, 0, len);
				out.flush();
			}
			bis.close();
            out.write("\r\n".getBytes());
            out.write(("\r\n" + END_MP_BOUNDARY).getBytes());
        } catch (IOException e) {
            throw new WeiboException(e);
        } finally {
            if (null != bis) {
                try {
                    bis.close();
                } catch (IOException e) {
                    throw new WeiboException(e);
                }
            }
        }
    }
    
    public static String encodeParameters(HashMap<String, String> httpParams) {
        if (null == httpParams || httpParams.size()==0) {
            return "";
        }
        
        boolean first=true;
        StringBuilder buf = new StringBuilder();
        Iterator<String> keyIter=httpParams.keySet().iterator();
        while(keyIter.hasNext())
        {
        	String key=keyIter.next();
        	 if (!first) {
                 buf.append("&");
             }
        	 first=false;
             try {
                 buf.append(URLEncoder.encode(key, "UTF-8")).append("=")
                         .append(URLEncoder.encode(httpParams.get(key), "UTF-8"));
             } catch (java.io.UnsupportedEncodingException neverHappen) {
             }
        	
        }
        
        return buf.toString();

    }
    
    /**
     * Read http requests result from response .
     * 
     * @param response
     *            : http response by executing httpclient
     * 
     * @return String : http response content
     */
    private static String read(HttpResponse response) throws WeiboException {
        String result = "";
        HttpEntity entity = response.getEntity();
        InputStream inputStream;
        try {
            inputStream = entity.getContent();
            ByteArrayOutputStream content = new ByteArrayOutputStream();

            Header header = response.getFirstHeader("Content-Encoding");
            if (header != null && header.getValue().toLowerCase().indexOf("gzip") > -1) {
                inputStream = new GZIPInputStream(inputStream);
            }

            // Read response into a buffered stream
            int readBytes = 0;
            byte[] sBuffer = new byte[512];
            while ((readBytes = inputStream.read(sBuffer)) != -1) {
                content.write(sBuffer, 0, readBytes);
            }
            // Return result from buffered stream
            result = new String(content.toByteArray());
            return result;
        } catch (IllegalStateException e) {
            throw new WeiboException(e);
        } catch (IOException e) {
            throw new WeiboException(e);
        }
    }
    

    public static HttpClient getNewHttpClient(Context context) {
        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            trustStore.load(null, null);

            SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

            HttpParams params = new BasicHttpParams();

            HttpConnectionParams.setConnectionTimeout(params, 10000);
            HttpConnectionParams.setSoTimeout(params, 10000);

            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

            SchemeRegistry registry = new SchemeRegistry();
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            registry.register(new Scheme("https", sf, 443));

            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

            // Set the default socket timeout (SO_TIMEOUT) // in
            // milliseconds which is the timeout for waiting for data.
            HttpConnectionParams.setConnectionTimeout(params, 5000);
            HttpConnectionParams.setSoTimeout(params, 5000);
            HttpClient client = new DefaultHttpClient(ccm, params);
            WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
            if (!wifiManager.isWifiEnabled()) {
                // 获取当前正在使用的APN接入点
                Uri uri = Uri.parse("content://telephony/carriers/preferapn");
                Cursor mCursor = context.getContentResolver().query(uri, null, null, null, null);
                if (mCursor != null && mCursor.moveToFirst()) {
                    // 游标移至第一条记录，当然也只有一条
                    String proxyStr = mCursor.getString(mCursor.getColumnIndex("proxy"));
                    if (proxyStr != null && proxyStr.trim().length() > 0) {
                        HttpHost proxy = new HttpHost(proxyStr, 80);
                        client.getParams().setParameter(ConnRouteParams.DEFAULT_PROXY, proxy);
                    }
                    mCursor.close();
                }
            }
            return client;
        } catch (Exception e) {
            return new DefaultHttpClient();
        }
    }

    public static class MySSLSocketFactory extends SSLSocketFactory {
        SSLContext sslContext = SSLContext.getInstance("TLS");

        public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException,
                KeyManagementException, KeyStoreException, UnrecoverableKeyException {
            super(truststore);

            TrustManager tm = new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                }

                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };

            sslContext.init(null, new TrustManager[] { tm }, null);
        }

        @Override
        public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
                throws IOException, UnknownHostException {
            return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
        }

        @Override
        public Socket createSocket() throws IOException {
            return sslContext.getSocketFactory().createSocket();
        }
    }
    
/************************************************内部类****************************************************************************/
	
	private static class myX509TrustManager implements X509TrustManager {
	    
	    public void checkClientTrusted(X509Certificate[] chain, String authType) {
	    }

	    public void checkServerTrusted(X509Certificate[] chain, String authType) {
	        System.out.println("cert: " + chain[0].toString() + ", authType: " + authType);
	    }

	    public X509Certificate[] getAcceptedIssuers() {
	        return null;
	    }
	}
	
	private static class myHostnameVerifier implements HostnameVerifier {

	    public boolean verify(String hostname, SSLSession session) {
	        System.out.println("Warning: URL Host: " + hostname + " vs. " + session.getPeerHost());
	        return true;
	    }
	}


}


